/*
* ============================================================================
*  Name        : example_005.cpp
*  Part of     : Finite state machine examples
*  Description : Parent child relationship between state machines
*  Version     : %version: %
*  
*
* ============================================================================
*/
#include "example_005.h"
#include "example_005.hxx" // State machine source code is here

/**
 * @file example_005.cpp
 *
 * @details
 * Scenario <br>
 *  @li Parent and child start one after another
 *  @li Child times out after 300ms and terminates
 *  @li Parents gets notification from the child and terminates itself
 * 
 *  Notice, parent state machine ( example_005.hxx ) lives forever unless: <br>
 *  @li Ev_Sys_Terminate is sent. See SystemStateMachine
 *  @li Child dies
 * 
 * @ingroup StateMachineExamples
 */
using namespace sea_examples;

// ----------------------------------------------------------------------------
// Create parent and child and let them run to completion
// ----------------------------------------------------------------------------
void sea_examples::launch_example_005( )
{
    SEA_TRACE_ENTRY( );

    {
        sea::ref< Parent > parent_sm;
        parent_sm << NEW Parent;

        if ( parent_sm->create( 0, Parent_src ) != eOk ){ /* See Error codes */ }
        if ( parent_sm->start( StateMachine::RunAsync ) != eOk ){ /* See Error codes */ }

        sea::ref< Child > child_sm;
        child_sm << NEW Child;

        if ( child_sm->create( 0 , Child_src ) != eOk ){ /* See Error codes */ }
        if ( child_sm->start( parent_sm.get( ), StateMachine::RunAsync ) != eOk ){ /* See Error codes */ }

        // Both parent and child run in 'async' mode, so wait for the completion here
        child_sm->wait_manager_to_finish( );
        parent_sm->wait_manager_to_finish( );
    }

    Engine::terminate( );
}

// ----------------------------------------------------------------------------
// Same as above, but the parent is forsed to terminate earlier then a child
// Scenario:
// - Parent and child start one after another
// - Send terminate command to parent before child times out
// - Child gets notification from the parent and terminates itself
// ----------------------------------------------------------------------------
void sea_examples::launch_example_0051( )
{
    SEA_TRACE_ENTRY( );

    Parent* parent_sm = NEW Parent;
    if ( parent_sm->create( 0, Parent_src ) != eOk ){ /* See Error codes */ }
    if ( parent_sm->start( StateMachine::RunAsync ) != eOk ){ /* See Error codes */ }

    Child* child_sm = NEW Child;
    if ( child_sm->create( 0 , Child_src ) != eOk ){ /* See Error codes */ }
    if ( child_sm->start( parent_sm, StateMachine::RunAsync ) != eOk ){ /* See Error codes */ }

    // Tell parent to terminate right away
    parent_sm->push_event( parent_sm->terminate_event_id( ) );

    // Both parent and child run in 'async' mode, so wait for the completion here
    child_sm->wait_manager_to_finish( );
    parent_sm->wait_manager_to_finish( );

    child_sm->release_ref( );
    parent_sm->release_ref( );

    Engine::terminate( );
}

// ----------------------------------------------------------------------------
// Same as above, with multiple instances
// ----------------------------------------------------------------------------
void sea_examples::launch_example_0052( )
{
    SEA_TRACE_ENTRY( );

    vector< StateMachine* > parents;
    vector< StateMachine* > children;

    int n = 3;

    for ( int i = 0; i < n; i++ )
    {
        Parent* parent_sm = NEW Parent;
        if ( parent_sm->create( 0, Parent_src ) != eOk ){ /* See Error codes */ }
        if ( parent_sm->start( StateMachine::RunAsync ) != eOk ){ /* See Error codes */ }
        parents.insert( parents.end( ), parent_sm );

        Child* child_sm = NEW Child;
        if ( child_sm->create( 0 , Child_src ) != eOk ){ /* See Error codes */ }
        if ( child_sm->start( parent_sm, StateMachine::RunAsync ) != eOk ){ /* See Error codes */ }
        children.insert( children.end( ), child_sm );
    }

    // Tell parents to terminate right away
    for ( int i = 0; i < n; i++ )
    {
        parents[ i ]->push_event( parents[ i ]->terminate_event_id( ) );
    }

    // Both parent and child run in 'async' mode, so wait for the completion here
    for ( int i = 0; i < n; i++ )
    {
        children[ i ]->wait_manager_to_finish( );
        parents[ i ]->wait_manager_to_finish( );

        children[ i ]->release_ref( );
        parents[ i ]->release_ref( );
    }

    Engine::terminate( );
}

